﻿using System;
using System.Windows.Media;
using System.Collections.Generic;

namespace ImageProcessing.Common
{
    public class IntegralImage
    {
        private readonly int _width;
        private readonly int _height;
        private readonly float[,] _imageMatrix;

        // NTSC conversion vablues
        private const float Red = 0.2989f;
        private const float Green = 0.5870f;
        private const float Blue = 0.1140f;

        // fast lookup
        private readonly Dictionary<int, float> _integralColour = new Dictionary<int, float>();

        public IntegralImage(int width, int height)
        {
            // init
            _width = width;
            _height = height;
            _imageMatrix = new float[_height, _width];
        }

        [Obsolete("clean up code, redundant methods below")]
        public void BuildIntegralImage(ref int[] argbImage)
        {
            // calc first row(we dont have to do top level)
            float rowSum = 0;
            for (int x = 0; x < _width; x++)
            {
                rowSum += GetIntegralColour(argbImage[x]);
                _imageMatrix[0, x] = rowSum;
            }

            // calc rest
            for (int y = 1; y < _height; y++)
            {
                rowSum = 0;
                for (int x = 0; x < _width; x++)
                {
                    rowSum += GetIntegralColour(argbImage[y * _width + x]);
                    _imageMatrix[y, x] = rowSum + _imageMatrix[y - 1, x];
                }
            }
        }

        [Obsolete("clean up code, redundant methods below")]
        public void BuildIntegralImage(ref byte[] yImage)
        {
            // calc first row(we dont have to do top level)
            float rowSum = 0;
            for (int x = 0; x < _width; x++)
            {
                rowSum += GetIntegralColour(yImage[x]);
                _imageMatrix[0, x] = rowSum;
            }

            // calc rest
            for (int y = 1; y < _height; y++)
            {
                rowSum = 0;
                for (int x = 0; x < _width; x++)
                {
                    rowSum += GetIntegralColour(yImage[y * _width + x]);
                    _imageMatrix[y, x] = rowSum + _imageMatrix[y - 1, x];
                }
            }
        }

        [Obsolete("todo cleanup")]
        private void Image(Action<float> GetIntColor)
        {


        }

        private float GetIntegralColour(byte yPixel)
        {
            return (float)yPixel / 255;
        }

        private float GetIntegralColour(int argbPixel)
        {
            float result = 0;

            if (_integralColour.TryGetValue(argbPixel, out result))
                return result;

            var argb = BitConverter.GetBytes(argbPixel);
            var a = argb[3];
            var r = argb[2];
            var g = argb[1];
            var b = argb[0];
            Color c = Color.FromArgb(a, r, g, b);

            result = (Red * r + Green * g + Blue * b) / 255f;

            _integralColour[argbPixel] = result;

            return result;
        }

        public float BoxIntegral(int row, int col, int rows, int cols)
        {
            int row1 = Math.Min(row, _height) - 1;
            int col1 = Math.Min(col, _width) - 1;
            int row2 = Math.Min(row + rows, _height) - 1;
            int col2 = Math.Min(col + cols, _width) - 1;

            float a = 0, b = 0, c = 0, d = 0;

            if (row1 >= 0 && col1 >= 0) a = _imageMatrix[row1, col1];
            if (row1 >= 0 && col2 >= 0) b = _imageMatrix[row1, col2];
            if (row2 >= 0 && col1 >= 0) c = _imageMatrix[row2, col1];
            if (row2 >= 0 && col2 >= 0) d = _imageMatrix[row2, col2];

            return Math.Max(0, a - b - c + d);
        }


        /// <summary>
        /// Get Haar Wavelet X repsonse
        /// </summary>
        public float HaarX(int row, int column, int size)
        {
            return BoxIntegral(row - size / 2, column, size, size / 2)
              - 1 * BoxIntegral(row - size / 2, column - size / 2, size, size / 2);
        }

        /// <summary>
        /// Get Haar Wavelet Y repsonse
        /// </summary>
        public float HaarY(int row, int column, int size)
        {
            return BoxIntegral(row, column - size / 2, size / 2, size)
              - 1 * BoxIntegral(row - size / 2, column - size / 2, size / 2, size);
        }
    }
}
